#!/bin/bash
#
# addnews
#
# News addition helper for the Dragora GNU/Linux-Libre website
# (https://www.dragora.org)
#
#
# Copyright (C) 2021 Michael Siegel
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


#### INCLUDES ####

. include/constants || exit 1
. include/subroutines || exit 1


#### CONSTANTS ####


#### GLOBAL PARAMETERS ####

action=add
date=
title=
url=


#### FUNCTIONS ####

_days_in_month() {

  local month="$1"
  local year="$2"  # Needs to be YYYY.
  local days_in_month=(31 28 31 30 31 30 31 31 30 31 30 31)

  month="${month#0}"  # Strip leading zeroes for use in arithmetic expansion
  if [[ "$month" -eq 2 ]]
  then
    # Give February 29 days if $year is a leap year:
    [[ ("$((year % 4))" -eq 0 && "$((year % 100))" -ne 0) || \
      "$((year % 400))" -eq 0 ]] && days_in_month[1]=29
  fi

  printf '%s' "${days_in_month["$((month - 1))"]}"
}

_date_valid () {

  local input="$1"
  local day=
  local month=
  local year=
  local days_max=
  local valid=1

  if [[ ! "$input" =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]]
  then
    valid=0
  else
    year="${input:0:4}"
    month="${input:5:2}"
    day="${input:8:2}"

    if (( 10#"$month" < 1 || 10#"$month" > 12 ))
    then
      _perr "invalid month -- '$month'"
      valid=0
    else
      days_max="$(_days_in_month "$month" "$year")"
      if (( 10#"$day" < 1 || 10#"$day" > 10#"$days_max" ))
      then
        _perr "invalid day of month -- '$day'"
        valid=0
      else
        date_unix_time="$(TZ="$TIMEZONE" \
          date -d "${year#0}-${month#0}-${day#0}" '+%s')"
        if (( 10#"$date_unix_time" < 0 ))
        then
          _perr "date out of range (negative Unix time) -- '$input'"
          valid=0
        fi
      fi
    fi
  fi

  [[ "$valid" -eq 0 ]] && return 1
  return 0
}

_prompt_date() {

  local input=
  local date_default; date_default="$(date +%Y-%m-%d)"

  while true
  do
    if [[ -z "$input" ]]
    then
      printf '%s\n' "Please enter the publishing date [$date_default]:"
      printf '%s\n' "$HELP_TIP_INTERACTIVE"
    fi

    read -rp "$PROMPT" input

    if [[ -z "$input" ]]
    then
      date="$date_default"
      break
    elif [[ "$input" = "$HELP_COMMAND" ]]
    then
      _show_help "$FUNCNAME"
    elif ! _date_valid "$input"  # _date_valid prints error messages.
    then
      printf '%s\n' "$HELP_TIP_INTERACTIVE"
    else
      date="$input"
      break
    fi
  done
}

_prompt_title() {

  local input=

  while true
  do
    if [[ -z "$input" ]]
    then
      printf '%s\n' 'Please enter a title:'
      printf '%s\n' "$HELP_TIP_INTERACTIVE"
    fi

    read -rp "$PROMPT" input

    if [[ -z "$input" ]]
    then
      continue
    elif [[ "$input" = "$HELP_COMMAND" ]]
    then
      _show_help "$FUNCNAME"
    else
      break
    fi
  done

  title="$input"
}

_prompt_url() {

  local input=
  local url_pattern='^https://lists\.nongnu\.org/archive/html/dragora-users/[0-9]{4}-[0-9]{2}/msg[0-9]+\.html$'
    # Hard-coded 'https' because plain HTTP access not available.
    # Kept number of digits before '.html' flexible because not sure if it's
    # constant.

  while true
  do
    if [[ -z "$input" ]]
    then
      printf '%s\n' 'Please enter a URL:'
      printf '%s\n' "$HELP_TIP_INTERACTIVE"
    fi

    read -rp "$PROMPT" input

    if [[ -z "$input" ]]
    then
      continue
    elif [[ "$input" = "$HELP_COMMAND" ]]
    then
      _show_help "$FUNCNAME"
    elif [[ ! ("$input" =~ $url_pattern) ]]
    then
      _perr "invalid URL -- '$input'"
    else
      break
    fi
  done

  url="$input"
}

_mk_news_item() {

  printf '  <li>%s\\n    <a href="%s">%s</a>\\n  </li>' "$date" "$url" "$title"
  # Escaping `\n` so the result can be used in sed.
}

_add_news() {

  local news_pg=

  local lang=
  for lang in $(_get_lang_dirs)
  do
    news_pg="${PAGES_DIR}/${lang}/$NEWS_PAGE"
    cp -a  -- "$news_pg" "$news_pg".old
    sed -i -- "s|<ul>|<ul>\n$(_mk_news_item)|" "$news_pg"
  done
  unset lang
}

_revert() {

  local news_pg=

  local lang=
  for lang in $(_get_lang_dirs)
  do
    news_pg="${PAGES_DIR}/${lang}/$NEWS_PAGE"
    if [[ -e "$news_pg".old ]]
    then
      mv -- "$news_pg".old "$news_pg" || return 1
    else
      _perr "cannot find backup file -- ${news_pg}.old"
    fi
  done
  unset lang
}

_show_help() {

  case "$1" in
    global)
cat <<'EOF'
Add a news item interactively

Usage:
    addnews [OPTIONS]

Options:
    -r  Revert latest news addition

    --help
        Show this help text and exit
EOF
    ;;
    *)
      printf '%s\n' "Sorry, no help text available."
    ;;
  esac
}


#### MAIN ####

## Environment checks

_env_checks || _abort

## Action

while [[ "$#" -gt 0 ]]
do
  case "$1" in
    -r)
      shift
      action=revert
    ;;
    --help)
      _show_help global
      exit
    ;;
    --)  # End of options
      shift
      break
    ;;
    *)
      _perr "invalid argument -- '$1'"
      exit 1
    ;;
  esac
done

if [[ "$action" = revert ]]
then 
  _revert || _abort
else
  _prompt_date || _abort
  _prompt_title || _abort
  _prompt_url || _abort
  _add_news || _abort
fi
